// BenchmarkDialog.h

#ifndef __BENCHMARK_DIALOG_H
#define __BENCHMARK_DIALOG_H

#include "Common/Archive/Bench.h"

#include "BenchmarkDialogRes.h"

#include "Common/System/Threading/SimpleWorkerPool.h"
#include "Common/System/Threading/Utility.h"
#include <memory>

struct CBenchInfo2 : public Extract::CBenchInfo
{
  void Init()  { GlobalTime = UserTime = 0; }
};

class CProgressSyncInfo
{
public:
  bool Stopped;
  bool Paused;
  bool Changed;
  UINT32 DictionarySize;
  UINT32 NumThreads;
  UINT64 NumPasses;
  // UINT64 NumErrors;
  //Common::System::Synchronization::CManualResetEvent _startEvent;
  Common::System::Threading::CEvent _startEvent;
  //Common::System::Synchronization::CCriticalSection CS;
  CComAutoCriticalSection CS;

  typedef Common::System::Threading::CScopeLockT<CComAutoCriticalSection> AutoLock;


  CBenchInfo2 CompressingInfoTemp;
  CBenchInfo2 CompressingInfo;
  UINT64 ProcessedSize;

  CBenchInfo2 DecompressingInfoTemp;
  CBenchInfo2 DecompressingInfo;

  CProgressSyncInfo()
  {
    if (_startEvent.Create() != S_OK)
      throw 3986437;
  }
  void Init()
  {
    Changed = false;
    Stopped = false;
    Paused = false;
    CompressingInfoTemp.Init();
    CompressingInfo.Init();
    ProcessedSize = 0;
    
    DecompressingInfoTemp.Init();
    DecompressingInfo.Init();

    NumPasses = 0;
    // NumErrors = 0;
  }

  void Stop()
  {
    //Common::System::Synchronization::CCriticalSectionLock lock(CS);
	AutoLock lock(CS);
    Stopped = true;
  }
  bool WasStopped()
  {
    //Common::System::Synchronization::CCriticalSectionLock lock(CS);
	AutoLock lock(CS);
	return Stopped;
  }
  void Pause()
  {
    //Common::System::Synchronization::CCriticalSectionLock lock(CS);
	AutoLock lock(CS);
    Paused = true;
  }
  void Start()
  {
    //Common::System::Synchronization::CCriticalSectionLock lock(CS);
	AutoLock lock(CS);
    Paused = false;
  }
  bool WasPaused()
  {
    //Common::System::Synchronization::CCriticalSectionLock lock(CS);
	AutoLock lock(CS);
    return Paused;
  }
  void WaitCreating() { _startEvent.WaitForObject(); }
};

class CBenchmarkDialog: public CDialogImpl<CBenchmarkDialog>,  public CIdleHandler
{
  CComboBox m_Dictionary;
  CComboBox m_NumThreads;
  UINT_PTR _timer;
  UINT32 _startTime;

  void OnRestartButton();
  void OnStopButton();
  
  void PrintTime();
  void PrintRating(UINT64 rating, UINT controlID);
  void PrintUsage(UINT64 usage, UINT controlID);
  void PrintResults(
      UINT32 dictionarySize,
      const CBenchInfo2 &info, UINT usageID, UINT speedID, UINT rpuID, UINT ratingID,
      bool decompressMode = false);

  UINT32 GetNumberOfThreads();
  UINT32 OnChangeDictionary();
  void OnChangeSettings();
public:
  enum { IDD = IDD_DIALOG_BENCHMARK};
	virtual BOOL OnIdle();
  CProgressSyncInfo Sync;

	BEGIN_MSG_MAP(CBenchmarkDialog)
		MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
		MESSAGE_HANDLER(WM_HELP, OnHelp)
		COMMAND_CODE_HANDLER(CBN_SELCHANGE, OnSelectionChange)
		COMMAND_ID_HANDLER(IDOK, OnOK)
		COMMAND_ID_HANDLER(IDCANCEL, OnCancel)
		COMMAND_ID_HANDLER(IDC_BUTTON_RESTART, OnRestartButton)
		COMMAND_ID_HANDLER(IDC_BUTTON_STOP, OnStopButton)		
	END_MSG_MAP()

	LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);
	LRESULT OnHelp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);
	LRESULT OnSelectionChange(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
	LRESULT OnOK(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
	{
	  EndDialog(wID);
		return 0;
	}	
	LRESULT OnCancel(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
	

	LRESULT OnRestartButton(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
	{		
		OnRestartButton();
		return 0;
	}

	LRESULT OnStopButton(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
	{		
		OnStopButton();
		return 0;
	}

  CBenchmarkDialog(): _timer(0) {}
 
  void MessageBoxError(LPCTSTR message)
  {
    MessageBox(message, _T("7-Zip"), MB_ICONERROR);
  }
};

HRESULT Benchmark(
    DECL_EXTERNAL_CODECS_LOC_VARS
	std::shared_ptr<Common::System::Threading::CSimpleWorkerPool> & pool,
	UINT32 numThreads, UINT32 dictionarySize, HWND hwndParent = NULL);

#endif
